home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / graphicgems4.lha / GemsIV / emboss.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-06  |  4.3 KB  |  158 lines

  1. /*
  2.  * ANSI C code from the article
  3.  * "Fast Embossing Effects on Raster Image Data"
  4.  * by John Schlag, jfs@kerner.com
  5.  * in "Graphics Gems IV", Academic Press, 1994
  6.  *
  7.  *
  8.  * Emboss - shade 24-bit pixels using a single distant light source.
  9.  * Normals are obtained by differentiating a monochrome 'bump' image.
  10.  * The unary case ('texture' == NULL) uses the shading result as output.
  11.  * The binary case multiples the optional 'texture' image by the shade.
  12.  * Images are in row major order with interleaved color components (rgbrgb...).
  13.  * E.g., component c of pixel x,y of 'dst' is dst[3*(y*xSize + x) + c].
  14.  *
  15.  * To compile a test program on an SGI:
  16.  *    cc -DMAIN emboss.c -lgl_s -lm -o emboss
  17.  * The code for the Emboss routine itself is portable to most machines.
  18.  */
  19.  
  20. #include <math.h>
  21. #include <sys/types.h>
  22.  
  23. void
  24. Emboss(
  25.     double azimuth, double elevation,    /* light source direction */
  26.     u_short width45,            /* filter width */
  27.     u_char *bump,            /* monochrome bump image */
  28.     u_char *texture, u_char *dst,    /* texture & output images */
  29.     u_short xSize, u_short ySize    /* image size */
  30. )
  31. {
  32.     long Nx, Ny, Nz, Lx, Ly, Lz, Nz2, NzLz, NdotL;
  33.     register u_char *s1, *s2, *s3, shade, background;
  34.     register u_short x, y;
  35.  
  36.     #define pixelScale 255.9
  37.  
  38.     /*
  39.      * compute the light vector from the input parameters.
  40.      * normalize the length to pixelScale for fast shading calculation.
  41.      */
  42.     Lx = cos(azimuth) * cos(elevation) * pixelScale;
  43.     Ly = sin(azimuth) * cos(elevation) * pixelScale;
  44.     Lz = sin(elevation) * pixelScale;
  45.  
  46.     /*
  47.      * constant z component of image surface normal - this depends on the
  48.      * image slope we wish to associate with an angle of 45 degrees, which
  49.      * depends on the width of the filter used to produce the source image.
  50.      */
  51.     Nz = (6 * 255) / width45;
  52.     Nz2 = Nz * Nz;
  53.     NzLz = Nz * Lz;
  54.  
  55.     /* optimization for vertical normals: L.[0 0 1] */
  56.     background = Lz;
  57.  
  58.     /* mung pixels, avoiding edge pixels */
  59.     dst += xSize*3;
  60.     if (texture) texture += xSize*3;
  61.     for (y = 1; y < ySize-1; y++, bump += xSize, dst += 3)
  62.     {
  63.     s1 = bump + 1;
  64.     s2 = s1 + xSize;
  65.     s3 = s2 + xSize;
  66.     dst += 3;
  67.     if (texture) texture += 3;
  68.     for (x = 1; x < xSize-1; x++, s1++, s2++, s3++)
  69.     {
  70.         /*
  71.          * compute the normal from the bump map. the type of the expression
  72.          * before the cast is compiler dependent. in some cases the sum is
  73.          * unsigned, in others it is signed. ergo, cast to signed.
  74.          */
  75.         Nx = (int)(s1[-1] + s2[-1] + s3[-1] - s1[1] - s2[1] - s3[1]);
  76.         Ny = (int)(s3[-1] + s3[0] + s3[1] - s1[-1] - s1[0] - s1[1]);
  77.  
  78.         /* shade with distant light source */
  79.         if ( Nx == 0 && Ny == 0 )
  80.         shade = background;
  81.         else if ( (NdotL = Nx*Lx + Ny*Ly + NzLz) < 0 )
  82.         shade = 0;
  83.         else
  84.         shade = NdotL / sqrt(Nx*Nx + Ny*Ny + Nz2);
  85.  
  86.         /* do something with the shading result */
  87.         if ( texture ) {
  88.         *dst++ = (*texture++ * shade) >> 8;
  89.         *dst++ = (*texture++ * shade) >> 8;
  90.         *dst++ = (*texture++ * shade) >> 8;
  91.         }
  92.         else {
  93.         *dst++ = shade;
  94.         *dst++ = shade;
  95.         *dst++ = shade;
  96.         }
  97.     }
  98.     if (texture) texture += 3;
  99.     }
  100. }
  101.  
  102. #ifdef MAIN
  103.  
  104. #define TEXTURE 1
  105.  
  106. main()
  107. {
  108.     #define xSize 200
  109.     #define ySize 200
  110.     u_char bump[ySize][xSize];
  111.     u_char texture[ySize][xSize][3], *txt = 0;
  112.     u_char dst[ySize][xSize][3];
  113.     int i, j;
  114.  
  115.     /* make a simple input image */
  116.     memset(bump, 0, sizeof(bump));
  117.     for(i = xSize/4; i < 3*xSize/4; i++)
  118.     for(j = ySize/4; j < 3*ySize/4; j++)
  119.         bump[j][i] = 128;
  120.  
  121.     #if TEXTURE
  122.     /* make a texture */
  123.     for(i = 0; i < xSize; i++)
  124.     for(j = 0; j < ySize; j++) {
  125.         texture[j][i][0] = random() >> (31 - 8);
  126.         texture[j][i][1] = random() >> (31 - 8);
  127.         texture[j][i][2] = random() >> (31 - 8);
  128.     }
  129.     txt = (u_char *)texture;
  130.     #endif
  131.  
  132.     /* emboss it */
  133.     memset(dst, 0, sizeof(dst));
  134.     #define dToR(d) ((d)*(M_PI/180))
  135.     Emboss(dToR(30), dToR(30), 3, (u_char *)bump, txt, (u_char *)dst,
  136.     xSize, ySize);
  137.  
  138.     /* display it (sgi component order is ABGR) */
  139.     prefsize(xSize, ySize);
  140.     winopen("emboss");
  141.     RGBmode();
  142.     gconfig();
  143.     for(i = 0; i < ySize; i++) {
  144.     u_long line[xSize];
  145.     u_char *lp = (u_char *)line;
  146.     for(j = 0; j < xSize; j++) {
  147.         *lp++ = 255;
  148.         *lp++ = dst[i][j][2];
  149.         *lp++ = dst[i][j][1];
  150.         *lp++ = dst[i][j][0];
  151.     }
  152.     lrectwrite(0, ySize-1 - i, xSize-1, ySize-1 - i, line);
  153.     }
  154.     sleep(30);
  155. }
  156.  
  157. #endif
  158.